﻿#include "OperatorsJunctionPoint.h"

#include "PickDataProvider/GUIPickInfo.h"
#include "PickDataProvider/PickedDataProvider.h"
#include "PickDataProvider/PickedData.h"
#include "GUIDialog/GUIJunctionDialog/SEAPointJunctionDialog.h"
#include "GUIDialog/GUIJunctionDialog/HybridPointJunctionDialog.h"
#include "GUIDialog/GUIJunctionDialog/FEPointJunctionDialog.h"

//#include "FITK_Kernel/FITKAppFramework/FITKAppFramework.h"
//#include "FITK_Kernel/FITKAppFramework/FITKGlobalData.h"
#include "FITK_Kernel/FITKAppFramework/FITKMessage.h"
#include "FITK_Component/FITKAcousticsModel/FITKAcousticsDiscModel.h"
#include "FITK_Component/FITKAcousticsModel/FITKAcousticsDiscNodeList.h"
#include "FITK_Component/FITKAcousticsModel/FITKAcousticsSEAModel.h"
#include "FITK_Component/FITKAcousticsModel/FITKAcousticsFEModel.h"
#include "FITK_Component/FITKAcousticsModel/FITKAbstractSEASubSys.h"
#include "FITK_Component/FITKAcousticsModel/FITKAbstractFESubSys.h"

#include "OperatorsInterface/GraphEventOperator.h"
#include "updateBrowserTable.h"

namespace ModelOper
{
    bool OperatorsJunctionPoint::execGUI()
    {
        if (_senderName == "actionCreateJunctionPoint") {
            GraphData::PickedDataProvider* provider = GraphData::PickedDataProvider::getInstance();
            if (provider == nullptr)return false;
            //清除拾取对象所有的连接
            QObject::disconnect(provider, SIGNAL(sig_pickedOver()), nullptr, nullptr);

            GUI::GUIPickInfoStru pickStr;
            pickStr._pickObjType = GUI::GUIPickInfo::PickObjType::POBJDiscNode;
            pickStr._pickMethod = GUI::GUIPickInfo::PickMethod::PMIndividually;
            GUI::GUIPickInfo::ClearPickInfo();
            GUI::GUIPickInfo::SetPickInfo(pickStr);

            connect(provider, SIGNAL(sig_pickedOver()), this, SLOT(slotPickOverEvent()));
        }
        else if (_senderName == "actionEditJunctionPoint") {
            this->editJunctionPointOper();
        }
        else if (_senderName == "actionDeleteBatchPoint") {
            this->deleteBatchPointOper();
        }
        return false;
    }

    bool OperatorsJunctionPoint::execProfession()
    {
        int objId = -1;
        this->argValue(objID_String, objId);

        // Added by ChengHaotian 刷新可视化对象。
        //@{
        EventOper::GraphEventOperator* operGraph = FITKOPERREPO->getOperatorT<EventOper::GraphEventOperator>("GraphPreprocess");
        if (operGraph)
        {
            operGraph->updateGraph(objId);
        }
        //@}

        //更新表格
        ModelOper::updateBrowserTable();


        return false;
    }

    void OperatorsJunctionPoint::slotPickOverEvent()
    {
        //获取拾取数据
        GraphData::PickedDataProvider* provider = GraphData::PickedDataProvider::getInstance();
        if (provider == nullptr)return;
        disconnect(provider, SIGNAL(sig_pickedOver()), this, SLOT(slotPickOverEvent()));
        QList<GraphData::PickedData*> pickList = provider->getPickedList();
        QList<int> idList = {};
        for (GraphData::PickedData* pickData : pickList) {
            if (pickData == nullptr)continue;
            for (auto str : pickData->getPickedDiscNodes()) {
                idList.append(str._id);
            }
        }
        GUI::GUIPickInfo::ClearPickInfo();
        //创建连接点
        this->createJunctionPointOper(idList);
    }

    void OperatorsJunctionPoint::createJunctionPointOper(QList<int> pointList)
    {
        //判断拾取数据
        QList<QPair<int, int>> subsys;
        if (!this->pickDataExtract(pointList, subsys))return;
        //获取类型
        int type = 0;
        if (!this->argValue<int>("JunctionType", type)) return;
        //创建修改界面
        QDialog* dialog = nullptr;
        if (type == Acoustics::FITKAbstractJunction::JunctionType::SEAPointJunction)
        {
            GUI::SEAPointJunctionDialog* junDialog = new GUI::SEAPointJunctionDialog(-1, this, true);
            junDialog->setSubsysIDs(subsys);
            junDialog->setNode(createJunctionPoint(pointList));
            dialog = junDialog;
        }
        else if (type == Acoustics::FITKAbstractJunction::JunctionType::HybridPointJunction)
        {
            GUI::HybridPointJunctionDialog* junDialog = new GUI::HybridPointJunctionDialog(-1, this, true);
            junDialog->setSubsysIDs(subsys);
            junDialog->setNode(createJunctionPoint(pointList));
            dialog = junDialog;
        }
        else if (type == Acoustics::FITKAbstractJunction::JunctionType::FEPointJunction)
        {
            GUI::FEPointJunctionDialog* junDialog = new GUI::FEPointJunctionDialog(-1, this, true);
            junDialog->setSubsysIDs(subsys);
            junDialog->setNode(createJunctionPoint(pointList));
            dialog = junDialog;
        }
        if (!dialog) return;
        dialog->show();
    }

    void OperatorsJunctionPoint::editJunctionPointOper()
    {
        //获取离散数据
        Acoustics::FITKAcousticsDiscModel* discModel = FITKAPP->getGlobalData()->getMeshData<Acoustics::FITKAcousticsDiscModel>();
        if (discModel == nullptr) return;
        //获取junction管理器
        Acoustics::FITKJunctionManager* junctionManager = discModel->getJunctionManager();
        if (!junctionManager) return;
        //获取junction数据
        int objID = -1;
        if (!this->argValue(objID_String, objID)) return;
        Acoustics::FITKAbstractJunction* pointJun = junctionManager->getDataByID(objID);
        if (!pointJun) return;
        //获取类型-创建修改界面
        QDialog* dialog = nullptr;
        Acoustics::FITKAbstractJunction::JunctionType type = pointJun->getJunctiontType();
        if (type == Acoustics::FITKAbstractJunction::JunctionType::SEAPointJunction)
            dialog = new GUI::SEAPointJunctionDialog(objID, this, false);
        else if (type == Acoustics::FITKAbstractJunction::JunctionType::HybridPointJunction)
            dialog = new GUI::HybridPointJunctionDialog(objID, this, false);
        else if (type == Acoustics::FITKAbstractJunction::JunctionType::FEPointJunction)
            dialog = new GUI::FEPointJunctionDialog(objID, this, false);
        //显示界面
        dialog->show();
    }

    void OperatorsJunctionPoint::deleteBatchPointOper()
    {
        //获取离散数据
        Acoustics::FITKAcousticsDiscModel* discModel = FITKAPP->getGlobalData()->getMeshData<Acoustics::FITKAcousticsDiscModel>();
        if (discModel == nullptr) return;
        //获取junction管理器
        Acoustics::FITKJunctionManager* junctionManager = discModel->getJunctionManager();
        if (!junctionManager) return;
        //移除连接点的数据
        int count = junctionManager->getDataCount();
        for (int i = count - 1; i >= 0; --i)
        {
            //获取点数据
            Acoustics::FITKAbstractJunction* pointJun = junctionManager->getDataByIndex(i);
            if (!pointJun) continue;
            //获取类型
            Acoustics::FITKAbstractJunction::JunctionType type = pointJun->getJunctiontType();
            if (!(type == Acoustics::FITKAbstractJunction::JunctionType::SEAPointJunction || type == Acoustics::FITKAbstractJunction::JunctionType::FEPointJunction
                || type == Acoustics::FITKAbstractJunction::JunctionType::HybridPointJunction)) continue;
            junctionManager->removeDataObj(pointJun);
        }
        //刷新渲染
        EventOper::GraphEventOperator* operGraph = FITKOPERREPO->getOperatorT<EventOper::GraphEventOperator>("GraphPreprocess");
        if (operGraph) {
            operGraph->updateJunctions();
        }
    }

    int OperatorsJunctionPoint::createJunctionPoint(QList<int>& points)
    {
        //获取离散数据
        Acoustics::FITKAcousticsDiscModel* discModel = FITKAPP->getGlobalData()->getMeshData<Acoustics::FITKAcousticsDiscModel>();
        if (discModel == nullptr && discModel->getSEAModel() == nullptr)return -1;
        Acoustics::FITKAcousticsDiscNodeList* nodeList = discModel->getNodes();
        if (nodeList == nullptr)return -1;
        if (points.size() == 1) {
            //如果选择点只有一个，返回原点
            return points[0];
        }
        else if (points.size() == 2) {
            Core::FITKNode* point1 = nodeList->getNodeByID(points[0]);
            Core::FITKNode* point2 = nodeList->getNodeByID(points[1]);
            double x = (point1->x() + point2->x()) / 2;
            double y = (point1->y() + point2->y()) / 2;
            double z = (point1->z() + point2->z()) / 2;
            return nodeList->addNode(x, y, z);
        }
        return -1;
    }

    bool OperatorsJunctionPoint::pickDataExtract(QList<int> pointIDs, QList<QPair<int, int>>& subsys)
    {
        if (pointIDs.isEmpty()) return false;
        //获取离散数据
        Acoustics::FITKAcousticsDiscModel* discModel = FITKAPP->getGlobalData()->getMeshData<Acoustics::FITKAcousticsDiscModel>();
        if (!discModel) return false;
        //获取SEA模型和FE模型
        Acoustics::FITKAcousticsSEAModel* seaModel = discModel->getSEAModel();
        Acoustics::FITKAcousticsFEModel* feModel = discModel->getFEModel();
        if (!seaModel || !feModel) return false;
        bool isExistSEA = false, isExistFE = false;
        for (int i = 0; i < pointIDs.size(); ++i)
        {
            QList<int> pointID;
            pointID.append(pointIDs.at(i));
            //获取关联的SEA子系统与FE子系统
            QList<Acoustics::FITKAbstractSEASubSys*> subSysSEAList = seaModel->getSEASubsysConnectedWithNodes(pointID, false);
            QList<Acoustics::FITKAbstractFESubSys*> subSysFEList = feModel->getFESubsysConnectedWithNodes(pointID, false);
            if (subSysFEList.isEmpty() && subSysSEAList.isEmpty())
            {
                AppFrame::FITKMessageError("Too few subsystems to create a manual point junction !");
                return false;
            }
            //SEA子系统
            for (Acoustics::FITKAbstractSEASubSys* sys : subSysSEAList) {
                if (sys == nullptr) continue;
                Acoustics::FITKAbstractSEASubSys::SEASubSysType type = sys->getSEASubSysType();
                if (type == Acoustics::FITKAbstractSEASubSys::SEASemiIInfiniteFluid || type == Acoustics::FITKAbstractSEASubSys::SEACavity
                    || type == Acoustics::FITKAbstractSEASubSys::SEASSNone)
                    continue;
                isExistSEA = true;
                subsys.append(QPair<int, int>(sys->getDataObjectID(), pointIDs.at(i)));
            }
            //FE子系统
            for (Acoustics::FITKAbstractFESubSys* sys : subSysFEList) {
                if (sys == nullptr) continue;
                isExistFE = true;
                subsys.append(QPair<int, int>(sys->getDataObjectID(), pointIDs.at(i)));
            }
        }
        //拾取数据判断
        Acoustics::FITKAbstractJunction::JunctionType type = Acoustics::FITKAbstractJunction::JunctionType::NoneJunction;
        if (isExistSEA && !isExistFE)
            type = Acoustics::FITKAbstractJunction::JunctionType::SEAPointJunction;
        else if (isExistFE && !isExistSEA)
            type = Acoustics::FITKAbstractJunction::JunctionType::FEPointJunction;
        else
            type = Acoustics::FITKAbstractJunction::JunctionType::HybridPointJunction;
        this->setArgs("JunctionType", (int)type);
        //子系统拾取判断
        if (subsys.size() < 2 || (pointIDs.size() == 1 && type == Acoustics::FITKAbstractJunction::JunctionType::FEPointJunction))
        {
            AppFrame::FITKMessageError("Too few subsystems to create a manual point junction !");
            return false;
        }
        else if (pointIDs.size() > 2)
        {
            AppFrame::FITKMessageError("Manual point junction creation failed !");
            return false;
        }
        else if (type == Acoustics::FITKAbstractJunction::JunctionType::FEPointJunction && pointIDs.size() == 2)
        {
            QList<QPair<int, int>> copySubsys = subsys;
            subsys.clear();
            subsys.append(copySubsys[0]);
            for (QList<QPair<int, int>>::iterator iter = copySubsys.begin(); iter != copySubsys.end(); ++iter)
            {
                if (iter->second == subsys.at(0).second || iter->first == subsys.at(0).first)continue;
                subsys.append(*iter);
            }
        }
        return true;
    }
}